package com.ctg.behavior.calc.impala.builder.retentions;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ctg.behavior.calc.impala.report.retentions.CtRetentionsReport;
import com.ctg.behavior.calc.utils.CtCalcPropertyUtils;
import com.ctg.behavior.common.consts.CtFieldConsts;
import com.ctg.behavior.common.retentions.CtRetentionsCalcData;
import com.ctg.behavior.common.retentions.CtRetentionsCell;
import com.ctg.behavior.common.retentions.CtRetentionsRow;
import com.ctg.behavior.utils.CtDateUtils;
import com.ctg.behavior.utils.CtDoubleUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CtRetentionsCalcResultBuilder0 {

	@Autowired
	private CtRetentionsRowKeyBuilder rowkeyBuilder;

	// 记录某一天的第0日查询结果Map信息
	// KEY: [byValues数组中的元素，使用@符号分隔连接起来] + "@" + fromDate(第0日日期)
	private static ThreadLocal<Map<String, LinkedHashMap<String, Object>>> tlFirstZeroDayMap = new ThreadLocal<>();
	// KEY: [byValues数组中的元素，使用@符号分隔连接起来] + "@" + fromDate(第几日日期)
	private static ThreadLocal<Map<String, LinkedHashMap<String, Object>>> tlSecondDayMap = new ThreadLocal<>();

	// KEY: (有两种组KEY方式)
	// KEY1. byValues数组中的元素，使用@符号分隔连接起来
	// KEY2. KEY1的subRows, KEY2为KEY1 + "@" + fromDate
	private static ThreadLocal<Map<String, CtRetentionsRow>> tlIndexRows = new ThreadLocal<>();

	public void resetResultBuilderTheadLocal() {
		Map<String, CtRetentionsRow> indexedRows = new HashMap<>();
		tlIndexRows.set(indexedRows);
		Map<String, LinkedHashMap<String, Object>> first0DayMap = new LinkedHashMap<>();
		tlFirstZeroDayMap.set(first0DayMap);
		Map<String, LinkedHashMap<String, Object>> secondDayMap = new LinkedHashMap<>();
		tlSecondDayMap.set(secondDayMap);
	}

	public CtRetentionsCalcData doBuilder(CtRetentionsCalcData calcData, List<LinkedHashMap<String, Object>> calcResult, CtRetentionsReport report) {

		// 1. 通用字段
		calcData.setAppId(report.getAppId());
		calcData.setBookmarkId(report.getBookmarkId());
		calcData.setRequestId(report.getRequestId());
		calcData.setReportUpdateTime(CtDateUtils.dateToString(new Date()));
		calcData.setDataUpdateTime(calcData.getDataUpdateTime());

		// 2. ByFields
		calcData.setByFields(report.getByFields());

		calcData.setHasFirstDay(true);

		// 3.
		calcData = this.innerBuilder(calcData, calcResult, report);

		return calcData;
	}

	public CtRetentionsCalcData innerBuilder(CtRetentionsCalcData calcData, List<LinkedHashMap<String, Object>> calcResult, CtRetentionsReport oneReport) {

		String whichDay = oneReport.getWhichDay();

		List<String> byFields = CtCalcPropertyUtils.getProperties(oneReport.getByFields());

		// 当查询结为空时，需要补充对应的查询记录
		log.info("format start:{}", JSON.toJSONString(calcResult));
		this.buildAndFormatCalcResult(oneReport, calcResult);
		log.info("format end  :{}", JSON.toJSONString(calcResult));

		Set<Entry<String, LinkedHashMap<String, Object>>> entries = tlSecondDayMap.get().entrySet();
		// for (LinkedHashMap<String, Object> oneCalcResult : calcResult) {
		for (Entry<String, LinkedHashMap<String, Object>> entry : entries) {

			LinkedHashMap<String, Object> oneCalcResult = entry.getValue();

			// 查找并且build对应的累计ROW，即为：rows[0]行
			CtRetentionsRow theSumRow = null;
			{
				String theSumRowKey = rowkeyBuilder.buildRowKey(byFields, oneCalcResult);
				theSumRow = tlIndexRows.get().get(theSumRowKey);
				if (null == theSumRow) {
					theSumRow = new CtRetentionsRow();
					// 填充byFields对应的分组值
					for (String oneByField : byFields) {
						theSumRow.getByValues().add(String.valueOf(oneCalcResult.get(oneByField)));
					}
					// 没有指定分组字段，则需要填充ALL
					if (theSumRow.getByValues().isEmpty()) {
						theSumRow.setByValue(CtFieldConsts.FIELD_KEY_ALL);
						theSumRow.getByValues().add(CtFieldConsts.FIELD_KEY_ALL);
					}
					for (int index = 0; index < oneReport.getMaxCellIndex(); index++) {
						CtRetentionsCell oneCell = new CtRetentionsCell();
						theSumRow.getCells().add(oneCell);
					}
					tlIndexRows.get().put(theSumRowKey, theSumRow);
					calcData.getRows().add(theSumRow);
				}
			}

			// 查找并且build对应的Day ROW
			CtRetentionsRow theDayRow = null;
			{
				String theDayRowKey = rowkeyBuilder.buildDayRowKey(whichDay, byFields, oneCalcResult);
				theDayRow = tlIndexRows.get().get(theDayRowKey);
				if (null == theDayRow) {
					theDayRow = new CtRetentionsRow();
					// 初始化 CELL
					theDayRow.setByValue(whichDay);
					theDayRow.getByValues().add(whichDay);
					for (int index = 0; index < oneReport.getMaxCellIndex(); index++) {
						CtRetentionsCell oneCell = new CtRetentionsCell();
						theDayRow.getCells().add(oneCell);
					}
					tlIndexRows.get().put(theDayRowKey, theDayRow);
					if (byFields.isEmpty()) {
						// 按【总体】查看
						calcData.getRows().add(theDayRow);
					} else {
						// 非【总体】查看
						theSumRow.getSubRows().add(theDayRow);
					}
				}
			}

			// 如果是第0日，则需要先找第一事件数量, 并累加到 累计行(总体或分组总体)
			if (true) {
				String theFirstEvent = oneReport.getFirstEvent().getEventId();
				String theZeroDayRowKey = rowkeyBuilder.buildDayRowKey(oneReport.getTheFirstEventFromDate(), byFields, oneCalcResult);
				Map<String, Object> theFirstEvent0DayResult = tlFirstZeroDayMap.get().get(theZeroDayRowKey);
				// 总人数：
				Long theFirstEventTotalPeople = 0L;
				if (null == theFirstEvent0DayResult) {
					log.warn("theFirstEvent0DayResult is null, eventId={}, calcResult={}", theFirstEvent, JSON.toJSONString(calcResult));
				} else {
					Object tobj = theFirstEvent0DayResult.get(CtFieldConsts.FIELD_KEY_TOTAL);
					if (null == tobj) {
						theFirstEventTotalPeople = 0L;
					} else {
						theFirstEventTotalPeople = Long.valueOf(tobj.toString());
					}
				}
				theDayRow.setTotalPeople(theFirstEventTotalPeople);
				// 总人数 累加到SUM ROW
				theSumRow.setTotalPeople(theSumRow.getTotalPeople() + theFirstEventTotalPeople);
			}

			// DAY ROW的CELL数据填充
			Long theSecondEventDyaTotal = Long.valueOf(oneCalcResult.get(CtFieldConsts.FIELD_KEY_TOTAL).toString());
			CtRetentionsCell theDayCell = theDayRow.getCells().get(0);
			theDayCell.setPeople(theSecondEventDyaTotal);
			theDayCell.setPercent(CtDoubleUtils.percent2Scale(theSecondEventDyaTotal, theDayRow.getTotalPeople()));

			// CELL数据累加到SUM ROW
			CtRetentionsCell theSumCell = theSumRow.getCells().get(0);
			theSumCell.setPeople(theSumCell.getPeople() + theDayCell.getPeople());
			theSumCell.setPercent(CtDoubleUtils.percent2Scale(theSumCell.getPeople(), theSumRow.getTotalPeople()));

		}

		return calcData;
	}

	private void buildAndFormatCalcResult(CtRetentionsReport oneReport, List<LinkedHashMap<String, Object>> calcResult) {

		String theFirstEvent = oneReport.getFirstEvent().getEventId();
		String theSecondEvent = oneReport.getSecondEvent().getEventId();

		List<String> byFields = CtCalcPropertyUtils.getProperties(oneReport.getByFields());
		String theFirstEventZeroDay = oneReport.getTheFirstEventFromDate();
		String theSecondEventDay = "";//oneReport.getTheEventFromDate();
		
		/********************************************************************************
		 * @note1:把本次计算结果集中的第一事件的第0日信息存入：tlFirstZeroDayMap
		 * @note2:并把[第一事件的第0日信息]对应的第二事件的
		 */
		for (LinkedHashMap<String, Object> oneCalcResult : calcResult) {
			if (!theFirstEvent.equals(oneCalcResult.get(CtFieldConsts.FIELD_KEY_EVENT))) {
				continue;
			}
			//
			String firstEvent0DayRowKey = rowkeyBuilder.buildDayRowKey(theFirstEventZeroDay, byFields, oneCalcResult);
			tlFirstZeroDayMap.get().put(firstEvent0DayRowKey, oneCalcResult);
			//
			String secondEventDayRowKey = rowkeyBuilder.buildDayRowKey(theSecondEventDay, byFields, oneCalcResult);
			LinkedHashMap<String, Object> secondEventDayMap = new LinkedHashMap<String, Object>();
			secondEventDayMap.putAll(oneCalcResult);

			secondEventDayMap.put(CtFieldConsts.FIELD_KEY_EVENT, theSecondEvent);
			secondEventDayMap.put(CtFieldConsts.FIELD_KEY_EVENT_DATE, theSecondEventDay);
			if (!oneReport.getIsWastage()) {
				secondEventDayMap.put(CtFieldConsts.FIELD_KEY_TOTAL, 0L);
			}

			tlSecondDayMap.get().put(secondEventDayRowKey, secondEventDayMap);
		}

		for (LinkedHashMap<String, Object> oneCalcResult : calcResult) {
			if (!theSecondEvent.equals(oneCalcResult.get(CtFieldConsts.FIELD_KEY_EVENT))) {
				continue;
			}
			String firstEvent0DayRowKey = rowkeyBuilder.buildDayRowKey(theFirstEventZeroDay, byFields, oneCalcResult);
			// 该第二事件的查询记录加入到TheadLocal
			String secondEventDayRowKey = rowkeyBuilder.buildDayRowKey(theSecondEventDay, byFields, oneCalcResult);
			tlSecondDayMap.get().put(secondEventDayRowKey, oneCalcResult);
			if (oneReport.getIsWastage()) {
				LinkedHashMap<String, Object> firstEvent0DayMap = tlFirstZeroDayMap.get().get(firstEvent0DayRowKey);
				Object totalObj = 0L;
				if (firstEvent0DayMap != null) {
					// 理论上此firstEvent0DayMap不为空
					totalObj = firstEvent0DayMap.get(CtFieldConsts.FIELD_KEY_TOTAL);
				}
				Long firstEvent0DayValue = Long.valueOf(totalObj.toString());
				totalObj = oneCalcResult.get(CtFieldConsts.FIELD_KEY_TOTAL);
				Long secondEvent0DayValue = Long.valueOf(totalObj.toString());
				Long theValue = firstEvent0DayValue - secondEvent0DayValue;
				theValue = theValue > 0 ? theValue : 0;
				oneCalcResult.put(CtFieldConsts.FIELD_KEY_TOTAL, theValue);
			}
		}
	}

}
